<html><head><title>LittleJS Stress Test</title>
<meta name=viewport content=width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0>
<link rel=icon type=image/png href=../../favicon.png>
</head><body>

<script src=../../engine/engine.all.min.js?78></script>
<script>

/*
    LittleJS Stress Test
    - Render over 50,000 sprites at 60 fps in Chrome
    - Uses glOverlay mode in Firefox to improve performance
    - Also plays music in the background with zzfxm
    - All code and the image is contained in this html file
    - Text displayed using a div so it appears on top in glOverlay mode
*/

'use strict';

// keep our own list of simple sprites and track fps
let sprites, timeMS, showFPS, statsDisplay, spriteColor, spriteAdditiveColor, musicSource;

///////////////////////////////////////////////////////////////////////////////

class TestObject extends EngineObject 
{
    constructor(pos)
    {
        super(pos, vec2(1), 0, vec2(16), 0, spriteColor);

        this.additiveColor = spriteAdditiveColor;
        this.setCollision(1, 1);
    }
}

///////////////////////////////////////////////////////////////////////////////
function gameInit()
{
    // create tile collision
    initTileCollision(vec2(80,50));
    for (let x = tileCollisionSize.x; x--;)
        setTileCollisionData(vec2(x,0), 1), setTileCollisionData(vec2(x,tileCollisionSize.y-1), 1);
    for (let y = tileCollisionSize.y; y--;)
        setTileCollisionData(vec2(0,y), 1), setTileCollisionData(vec2(tileCollisionSize.x-1,y), 1);

    // set things up
    cameraScale = 16;
    cameraPos = tileCollisionSize.scale(.5);
    mainCanvas.style.background = '#555';
    sprites = [];
    gravity = -.01;

    // display stats using a div so when using glOverlay it still appears on top
    document.body.appendChild(statsDisplay = document.createElement('div'));
    statsDisplay.style = 'position:absolute;width:100%;top:50%;left:50%;transform:translate(-50%,-50%);font-size:4em;text-align:center;font-family:arial;user-select:none';
}

///////////////////////////////////////////////////////////////////////////////
function gameUpdate()
{
    if (!musicSource && mouseWasPressed(0))
        musicSource = music.play();

    // mouse click = change color
    if (mouseWasPressed(0) || mouseIsDown(2))
        spriteColor = randColor(), spriteAdditiveColor = randColor(new Color(.5,.5,.5, 0), new Color(0,0,0,0));

    // right click = drop test object
    if (mouseIsDown(2))
        new TestObject(mousePos);

    // mouse hold = add objects
    if (mouseIsDown(0))
        for (let i=100;i--;)
            sprites.push({
                pos:mousePos.add(randInCircle(2)),
                angle:rand(), 
                velocity:randInCircle(.2),
                color:spriteColor = spriteColor.mutate(), 
                additiveColor:spriteAdditiveColor.mutate()
            });
    
    // mouse wheel = zoom
    cameraScale = clamp(cameraScale*(1-mouseWheel/10), 1e3, 1);
}

///////////////////////////////////////////////////////////////////////////////
function gameUpdatePost()
{
}

///////////////////////////////////////////////////////////////////////////////
function gameRender()
{
    // track fps and update stats
    const frameTimeMS = Date.now();
    showFPS = lerp(.05, 1e3/(frameTimeMS - timeMS||1), showFPS);
    timeMS = frameTimeMS;

    const spriteCount = sprites.length
    const objectCount = engineObjects.length;
    statsDisplay.innerText = 
        spriteCount + objectCount ?
            spriteCount + ' Sprites\n' 
            + objectCount + ' Objects\n' 
            + showFPS.toFixed(1) + ' FPS'
        : 'LittleJS Stress Test\nLeft Click = Add Particles\nRight Click = Add Objects';

    const size = vec2(.5);
    for (const sprite of sprites)
    {
        // keep sprites above 0
        sprite.pos.y = max(sprite.pos.y, 0);

        // apply gravity
        sprite.velocity.y += gravity;
        
        // apply velocity
        sprite.pos = sprite.pos.add(sprite.velocity);

        // bounce
        if (sprite.pos.y < 0)
            sprite.velocity.y = rand(1,.5);
        if (sprite.pos.x < 0)
            sprite.pos.x = 0, sprite.velocity.x *= -1;
        if (sprite.pos.x > tileCollisionSize.x)
            sprite.pos.x = tileCollisionSize.x, sprite.velocity.x *= -1;

        // rotate sprite
        sprite.angle += .01*sign(sprite.velocity.x);

        // draw the sprite
        glDraw(sprite.pos.x, sprite.pos.y, 1, 1, sprite.angle, 0, 0, 1, 1, 
            sprite.color.rgbaInt(), sprite.additiveColor.rgbaInt());
    }
}

///////////////////////////////////////////////////////////////////////////////
function gameRenderPost()
{
}

///////////////////////////////////////////////////////////////////////////////
// load tiles image via url data
const tilesImageData = '';

///////////////////////////////////////////////////////////////////////////////
// Startup LittleJS Engine
engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, tilesImageData);

///////////////////////////////////////////////////////////////////////////////
// music - Depp Loop
const music = new Music([[[,0,77,,,.7,2,.41,,,,,,,,.06],[,0,43,.01,,.3,2,,,,,,,,,.02,.01],[,0,170,.003,,.008,,.97,-35,53,,,,,,.1],[.8,0,270,,,.12,3,1.65,-2,,,,,4.5,,.02],[,0,86,,,.1,,.7,,,,.5,,6.7,1,.05],[,0,41,,.05,.4,2,0,,,9,.01,,,,.08,.02],[,0,2200,,,.04,3,2,,,800,.02,,4.8,,.01,.1],[.3,0,16,,,.3,3]],[[[1,-1,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33],[3,1,22,,,,,,,,,,,,,,,,,,,,,,,,,,,,24,,,,24,,,,,,,,,,,,,,,,,,,,,,,,22,,22,,22,,,,],[5,-1,21,,,,,,,,,,,,,,,,,,,,,,,,,,,,24,,,,23,,,,,,,,,,,,,,,,,,,,,,,,24,,23,,21,,,,],[,1,21,,,,,,,,,,,,,,,,,,,,,,,,,,,,24,,,,23,,,,,,,,,,,,,,,,,,,,,,,,24,,23,,21,,,,]],[[1,-1,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33],[3,1,24,,,,,,,,27,,,,,,,,,,,,,,,,27,,,,24,,,,24,,,,,,,,27,,,,,,,,,,,,,,,,24,,24,,24,,,,],[5,-1,21,,,,,,,,,,,,,,,,,,,,,,,,,,,,24,,,,23,,,,,,,,,,,,,,,,,,,,,,,,24,,23,,21,,,,],[,1,21,,,,,,,,,,,,,,,,,,,,,,,,,,,,24,,,,23,,,,,,,,,,,,,,,,,,,,,,,,24,,23,,21,,,,],[6,1,,,34,34,34,,,,,,34,34,,,,,34,,,,34,34,,,,,34,,,,34,,,,34,34,34,,,,,,34,,,,,,34,34,,,34,34,,,,,,,,,34,34],[4,1,,,,,,,24,,,,,,24,,24,,,,24,,,,24,,,,,,,,,,,,,,,,24,,,,,,24,,24,,,,24,,,,24,,,,,,,,,,]],[[1,-1,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33,23,23,35,23,23,36,23,23,35,23,23,36,23,23,35,35,23,23,35,23,23,35,23,23,36,23,23,35,23,23,36,36],[5,-1,21,,,19,,,21,,,,,,,,,,21,,,19,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,],[3,1,24,,,24,,,24,,,,,,,,,,24,,,24,,,24,,,,24.75,24.5,24.26,24.01,24.01,24.01,,,,,25,,,,,,,,25,,,,,,,,25,,,,,,,,25,25,25,25],[4,-1,,,,,,,,,,,,,,,,,,,,,,,,,,,24.75,24.5,24.26,24.01,24.01,24.01,24.01,24,,24,24,,24,24,24,24,,24,24,,24,,24,24,,24,24,,24,24,24,24,,24,24,,24,24],[7,-1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,23,,21,23,,35,,23,,21,23,,35,,35,,23,,21,23,,35,,21,23,,35,,21,23,,,],[6,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,34,36,34,,33,34,34,36,31,36,34,,31,34,32,,33,36,34,,31,34,34,36,33,36,33,,31,,,]],[[1,-1,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33,21,21,33,21,21,33,21,21,33,21,21,33,21,21,33,33,17,17,29,17,17,29,17,17,29,17,17,29,17,17,29,29,17,17,29,17,17,29,17,17,29,17,17,29,17,17,29,29],[4,1,24,24,,24,24,,24,24,24,24,,24,24,,24,,24,24,,24,24,,24,24,24,24,,24,24,,24,24,24,24,,24,24,,24,24,24,,,24,24,,24,,24,24,,24,24,,24,24,24,24,,24,24,,24,24],[7,-1,21,,19,21,,33,,21,,19,21,,33,,33,,21,,19,21,,33,,21,,19,21,,33,,33,,17,,17,17,29,17,17,29,17,,17,17,29,17,17,29,17,,17,17,29,17,17,29,17,,17,17,29,17,17,29],[2,1,,34,34,34,,34,34,34,,34,34,34,,34,34,34,,34,34,34,,34,34,34,,34,34,34,,34,,,,34,34,34,,34,34,34,,34,34,34,,34,34,34,,34,34,34,,34,34,34,,34,34,34,,34,,,],[6,1,,,36,,,,,,36,,36,,,,,,,,36,,,,,,36,,36,,,,,,,,36,,,,,,,,,,,,,,,,36,,,,,,36,,36,,,,,,],[3,1,,,,,25,,,,,,,,25,,,,,,,,25,,,,,,,,25,25,25,25,,,,,25,,,,,25,,,25,,,,,,,,25,,,,,,,,25,25,25,25]],[[1,-1,14,14,26,14,14,26,14,14,26,14,14,26,14,14,26,26,14,14,26,14,14,26,14,14,26,14,14,26,14,14,26,26,17,17,29,17,17,29,17,17,29,17,17,29,17,17,29,29,19,19,31,19,19,31,19,19,31,19,19,31,19,19,31,31],[4,1,24,24,,24,24,,24,24,24,24,,24,24,,24,,24,24,,24,24,,24,24,24,24,,24,24,,24,24,24,24,,24,24,,24,24,24,24,,24,24,,36,,24,24,,24,24,,24,24,24,24,,24,24,,24,24],[7,-1,14,,14,14,26,14,14,26,14,,14,14,26,14,14,26,14,,14,14,26,14,14,26,14,,14,14,26,14,14,26,17,,17,17,29,17,17,29,17,,17,17,29,17,17,29,19,,19,19,31,19,19,31,19,,19,19,31,19,19,31],[2,1,,36,36,36,,36,36,36,,36,36,36,,36,36,36,,36,36,36,,36,36,36,,36,36,36,,36,,,,36,36,36,,36,36,36,,36,36,36,,36,36,36,,36,36,36,,36,36,36,,36,36,36,,36,,,],[3,1,,,,,25,,,,,,,,25,,,,,,,,25,,,,,,,,25,25,25,25,,,,,25,,,,,,,,25,,,,,,,,25,,,,,,,,25,25,25,25],[6,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,34,,,,,,34,,34,,,,,,,,34,,,,,,34,,34,,,,,,]]],[0,1,1,2,3,4,4]]);

</script>